#pragma once

#include <memory>
#include <sstream>
#include <string>
#include "IR.h"
#include "IRBuilder.h"
#include "SysYBaseVisitor.h"
#include "SysYParser.h"
#include "scope.h"


// push

namespace sysy
{
    class SysYIRGenerator : public SysYBaseVisitor
    {
    private:
        std::unique_ptr<Module> module;
        IRBuilder builder;
        Scope scope;

        std::vector<BasicBlock *> loopEntry;
        std::vector<BasicBlock *> loopExit;
        // 加两个量，来标明（while，if）的前一个块和后一个块,帮助lAndExp编写
        std::stack<BasicBlock *> trueExit;
        std::stack<BasicBlock *> falseExit;

    public:
        SysYIRGenerator() = default;

        static std::string new_reg_name()
        {
            static int regNum = 0;
            return std::string("%") + std::to_string(regNum++);
        }

        static std::string to_hex(float input)
        {
            double i = input;
            auto ii = *(unsigned long long *)&i;
            std::ostringstream o_s;
            o_s << std::hex << ii;
            auto name = o_s.str();
            while (name.size() < 16)
                name = "0" + name;
            //        auto name = std::to_string(*(unsigned long long *) &i);
            return "0x" + name;
        }

    public:
        std::any visitCompUnit(SysYParser::CompUnitContext *ctx) override;
        std::any visitBType(SysYParser::BTypeContext *ctx) override;
        std::any visitBlock(SysYParser::BlockContext *ctx) override;
        std::any visitBlockItem(SysYParser::BlockItemContext *ctx) override;
        std::any visitDecl(SysYParser::DeclContext *ctx) override;
        std::any visitFuncDef(SysYParser::FuncDefContext *ctx) override;
        std::any visitFuncType(SysYParser::FuncTypeContext *ctx) override;
        std::any visitNumAsPri(SysYParser::NumAsPriContext *ctx) override;
        std::any visitPriAsUna(SysYParser::PriAsUnaContext *ctx) override;
        std::any visitUnaAsMul(SysYParser::UnaAsMulContext *ctx) override;
        std::any visitMulAsAdd(SysYParser::MulAsAddContext *ctx) override;
        std::any visitExp(SysYParser::ExpContext *ctx) override;

        std::any visitRelAddAsRel(SysYParser::RelAddAsRelContext *ctx) override;
        std::any visitAddAsRel(SysYParser::AddAsRelContext *ctx) override;
        std::any visitEqRelAsEq(SysYParser::EqRelAsEqContext *ctx) override;
        std::any visitRelAsEq(SysYParser::RelAsEqContext *ctx) override;
        std::any visitLAndEqAsLAnd(SysYParser::LAndEqAsLAndContext *ctx) override;
        std::any visitEqAsLAnd(SysYParser::EqAsLAndContext *ctx) override;
        std::any visitLOrLAndAsLOr(SysYParser::LOrLAndAsLOrContext *ctx) override;
        std::any visitLAndAsLOr(SysYParser::LAndAsLOrContext *ctx) override;
        std::any visitLOrAsCond(SysYParser::LOrAsCondContext *ctx) override;

        std::any visitStmtAssign(SysYParser::StmtAssignContext *ctx) override;
        std::any visitStmtExp(SysYParser::StmtExpContext *ctx) override;
        std::any visitStmtReturn(SysYParser::StmtReturnContext *ctx) override;
        std::any visitStmtContinue(SysYParser::StmtContinueContext *ctx) override;
        std::any visitStmtBreak(SysYParser::StmtBreakContext *ctx) override;
        std::any visitStmtWhile(SysYParser::StmtWhileContext *ctx) override;



        std::any visitOpUnaAsUna(SysYParser::OpUnaAsUnaContext *ctx) override;
        std::any visitMulUnaAsMul(SysYParser::MulUnaAsMulContext *ctx) override;
        std::any visitAddMulAsAdd(SysYParser::AddMulAsAddContext *ctx) override;
        std::any visitLVal(SysYParser::LValContext *ctx) override;
        std::any visitLValAsPri(SysYParser::LValAsPriContext *ctx) override;
        std::any visitExpAsPri(SysYParser::ExpAsPriContext *ctx) override;
        std::any visitStmtIfElse(SysYParser::StmtIfElseContext *ctx) override;
        std::any visitInitVal(SysYParser::InitValContext *ctx) override;
        std::any visitFuncCallAsUna(SysYParser::FuncCallAsUnaContext *ctx) override;
    }; // class SysYIRGenerator
} // namespace sysy
